package com.example.szl7033.camera_1_preview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.ImageFormat;
import android.util.Log;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.hardware.Camera;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback , Camera.PreviewCallback {

    private SurfaceHolder mHolder;//界面控制器
    private Camera mCamera;//相机

    private Camera.Size previewSize = null; //预览尺寸
    public Camera.Size pictureSize = null; //照片尺寸

    private String TAG = "shi_CameraPreview";

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();//获取控制器实例
        mHolder.addCallback(this);//将当前预览类添加在控制器中
        mCamera.setDisplayOrientation(90);//旋转90度,摄像头传感器方向与局部坐标系y正方向，竖屏

    }

    //重写预览界面创建回调函数
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.

        //获取用来显示预览的界面的大小，根据大小设置照片尺寸和预览尺寸
        //Log.d(TAG,"preview:" + String.valueOf(getWidth()) + "*" + String.valueOf(getHeight()));

        try {
            mCamera.setPreviewDisplay(holder);//设置预览内容，绑定Camera和SurfaceHolder
            mCamera.setPreviewCallback(this);   //设置预览回调
            updateCameraParameters();   //设置（照片/预览/控件）尺寸
            mCamera.startPreview();//开始预览
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    //重写预览界面销毁回调函数
    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.

        mCamera.stopPreview();
        mCamera.setPreviewCallback(null);//注销预览回调
    }

    //重写预览界面改变回调函数
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        //Log.d(TAG,"surface changed =====");

        if (mHolder.getSurface() == null){
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();//停止预览
        } catch (Exception e){
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.setPreviewCallback(this);   //设置预览回调
            updateCameraParameters();   //设置（照片/预览/控件）尺寸
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }

    //设置相机参数（尺寸，格式……） 横屏 width > height
    public void updateCameraParameters(){
        if(mCamera == null){
            return;
        }

        //获取比例标准，此处，按照竖屏模式（因为竖屏后，SurfaceView 的宽高发生对调了）
        float ratio = (float) getHeight() / getWidth();

        //获取修改参数的实例
        Camera.Parameters p = mCamera.getParameters();

        //设置照片尺寸
        Camera.Size realSize = null;
        float r = 0;
        List<Camera.Size> supportedSizes = p.getSupportedPictureSizes();
        for(Camera.Size size : supportedSizes){
            float f = (float) size.width / size.height;
            if(((f > ratio)?(f - ratio):(ratio - f)) < ((r > ratio)?(r - ratio):(ratio - r))){
                realSize = size;
                r = f;
            }
        }
        assert realSize != null;
        Log.d(TAG,"real picture size : " + String.valueOf(realSize.width) + "*" + String.valueOf(realSize.height));
        p.setPictureSize(realSize.width,realSize.height);
        pictureSize = realSize; //获取照片尺寸
        //设置预览尺寸
        realSize = null;
        r = 0;
        supportedSizes.clear();
        supportedSizes = p.getSupportedPreviewSizes();
        for(Camera.Size size : supportedSizes){
            float f = (float) size.width / size.height;
            if(((f > ratio)?(f - ratio):(ratio - f)) < ((r > ratio)?(r - ratio):(ratio - r))){
                realSize = size;
                r = f;
            }
        }
        assert realSize != null;
        Log.d(TAG,"real preview size : " + String.valueOf(realSize.width) + "*" + String.valueOf(realSize.height));
        p.setPreviewSize(realSize.width,realSize.height);
        previewSize = realSize; //获取预览尺寸
        //设置照片格式
        p.setPictureFormat(ImageFormat.JPEG);
        //设置预览格式
        p.setPreviewFormat(ImageFormat.NV21);
        //设置预览帧率
        p.setPreviewFrameRate(30);

        //设置对焦模式
        p.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);    //用于拍照的连续自动对焦模式

        //应用参数
        mCamera.setParameters(p);

    }

    //预览帧处理函数
    public void onGetYuvFrame(byte[] bytes){
        @SuppressLint("SdCardPath") String path = "/sdcard/a_" + previewSize.width + "x" + previewSize.height + ".nv21";
        File tempFile = new File(path);  //创建文件对象
        try{
            if(! tempFile.exists()){
                //创建文件
                try{
                    FileOutputStream out = new FileOutputStream(tempFile);  //若文件不存在，则创建并写入第一帧数据
                    out.write(bytes);
                    out.close();
                    //Log.d(TAG,"create_file_succeed");
                }catch (IOException e){
                    e.printStackTrace();
                    Log.d(TAG,"create_file__fail");
                }
            } else{
                //追加数据
                RandomAccessFile randomFile = new RandomAccessFile(tempFile,"rw");  //若文件存在，则以追加的方式写入数据
                long fileLength = randomFile.length();
                randomFile.seek(fileLength);
                randomFile.write(bytes);
                randomFile.close();
                //Log.d(TAG,"store_normal");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.d(TAG,"store_file");
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG,"store_io");
        }
    }

    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        //添加预览帧处理
        //Log.d(TAG,"preview frame");
        onGetYuvFrame(bytes);
    }
}

